<!doctype html><html lang=en-us dir=ltr><head><meta charset=UTF-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=description content="[TOC]
命令 # Django 整合进 pytest测试 # pip install pytest-django pytest -s -vv .\tests\test_step2.py --rootdir X:\Code\workflows\ --ds project.settings rootdir 指定项目根目录 ds 指向django setting.py 文件 一、为什么需要pytest # helps you write better programs
提高阅读理解代码效率 提高debug效率 提高开发效率 保证交付代码质量 简单例子 # 入门例子:
了解使用test文件命名格式: test_前缀 了解断言assert 了解测试输出 # content of test_sample.py def inc(x): return x + 1 def test_answer(): assert inc(3) == 5 输出
$ pytest =========================== test session starts ============================ platform linux -- Python 3."><meta name=theme-color content="#FFFFFF"><meta name=color-scheme content="light dark"><meta property="og:title" content><meta property="og:description" content="[TOC]
命令 # Django 整合进 pytest测试 # pip install pytest-django pytest -s -vv .\tests\test_step2.py --rootdir X:\Code\workflows\ --ds project.settings rootdir 指定项目根目录 ds 指向django setting.py 文件 一、为什么需要pytest # helps you write better programs
提高阅读理解代码效率 提高debug效率 提高开发效率 保证交付代码质量 简单例子 # 入门例子:
了解使用test文件命名格式: test_前缀 了解断言assert 了解测试输出 # content of test_sample.py def inc(x): return x + 1 def test_answer(): assert inc(3) == 5 输出
$ pytest =========================== test session starts ============================ platform linux -- Python 3."><meta property="og:type" content="article"><meta property="og:url" content="http://example.org/docs/programmer/base/pytest-%E6%B5%8B%E8%AF%95/"><meta property="article:section" content="docs"><title>Py Test 测试 | Ian's Blog</title>
<link rel=manifest href=/manifest.json><link rel=icon href=/favicon.png type=image/x-icon><link rel=stylesheet href=/book.min.c58292d36b18b675680ab9baea2029204537b839ea72f258746ec0f32ce8d6c8.css integrity="sha256-xYKS02sYtnVoCrm66iApIEU3uDnqcvJYdG7A8yzo1sg=" crossorigin=anonymous><script defer src=/flexsearch.min.js></script><script defer src=/en.search.min.569e34257b6d9d9d98bef2eba3a64a9a25f6edeb684dcfd9d09d6515476ff4fa.js integrity="sha256-Vp40JXttnZ2YvvLro6ZKmiX27etoTc/Z0J1lFUdv9Po=" crossorigin=anonymous></script></head><body dir=ltr><input type=checkbox class="hidden toggle" id=menu-control>
<input type=checkbox class="hidden toggle" id=toc-control><main class="container flex"><aside class=book-menu><div class=book-menu-content><nav><h2 class=book-brand><a class="flex align-center" href=/><span>Ian's Blog</span></a></h2><div class=book-search><input type=text id=book-search-input placeholder=Search aria-label=Search maxlength=64 data-hotkeys=s/><div class="book-search-spinner hidden"></div><ul id=book-search-results></ul></div><ul><li class=book-section-flat><a href=/docs/programmer/>程序员笔记</a><ul><li><input type=checkbox id=section-52f633cba5cf47818d8ec01e928396f2 class=toggle checked>
<label for=section-52f633cba5cf47818d8ec01e928396f2 class="flex justify-between"><a role=button>Base</a></label><ul><li><a href=/docs/programmer/base/k8s-%E9%85%8D%E5%A5%97%E8%AF%B4%E6%98%8E/>k8s 配套说明</a></li><li><a href=/docs/programmer/base/k8s-%E6%8A%80%E6%9C%AF%E5%88%86%E4%BA%AB/>k8s技术分享</a></li><li><a href=/docs/programmer/base/k8s%E5%B8%B8%E7%94%A8%E5%91%BD%E4%BB%A4%E5%92%8C%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6%E8%A7%A3%E6%9E%90/>k8s学习-常用命令和配置文件</a></li><li><a href=/docs/programmer/base/pypi/>PyPi</a></li><li><a href=/docs/programmer/base/tipsofweb/>Nginx高可用</a></li><li><a href=/docs/programmer/base/for_china/>各个软件换源</a></li><li><a href=/docs/programmer/base/tipsofdebugers/>tips Of Debuggers</a></li><li><a href=/docs/programmer/base/notesdjango/>Django的建站的(｡･･)ﾉﾞ</a></li><li><a href=/docs/programmer/base/tipsofvim/>tip Of vim</a></li><li><a href=/docs/programmer/base/editer/>编辑器使用</a></li><li><a href=/docs/programmer/base/noteoflinux/>Linux</a></li><li><a href=/docs/programmer/base/argo-workflow%E6%80%A7%E8%83%BD%E6%B5%8B%E8%AF%95%E5%92%8C%E4%BD%BF%E7%94%A8%E5%9C%BA%E6%99%AF%E5%88%86%E6%9E%90/>Argo Workflow性能测试和使用场景分析</a></li><li><a href=/docs/programmer/base/argo-%E4%BD%BF%E7%94%A8%E8%AE%B0%E5%BD%95/>Argo 使用记录</a></li><li><a href=/docs/programmer/base/kafka-%E5%AE%89%E8%A3%85%E5%92%8C%E4%BD%BF%E7%94%A8/>Kafka 安装和使用</a></li><li><a href=/docs/programmer/base/paramiko-%E4%BD%BF%E7%94%A8-sshsftp/>Paramiko 使用 Ssh&amp;sftp</a></li><li><a href=/docs/programmer/base/pytest-%E6%B5%8B%E8%AF%95/ class=active>Py Test 测试</a></li><li><a href=/docs/programmer/base/sonar-%E4%BB%A3%E7%A0%81%E9%9D%99%E6%80%81%E6%A3%80%E6%9F%A5/>Sonar 代码静态检查</a></li><li><a href=/docs/programmer/base/%E5%B0%8F%E5%91%BD%E4%BB%A4/>小命令</a></li><li><a href=/docs/programmer/base/tip_dgraph/>Dgraph</a></li><li><a href=/docs/programmer/base/noteoffmtdata/>数据格式笔记</a></li></ul></li><li><input type=checkbox id=section-de7bfad1d124522974cdf8addfbb23f2 class=toggle>
<label for=section-de7bfad1d124522974cdf8addfbb23f2 class="flex justify-between"><a role=button>Net</a></label><ul><li><a href=/docs/programmer/net/uwsgi-%E5%A4%84%E7%90%86%E8%AE%B0%E5%BD%95/>uwsgi 处理记录</a></li><li><a href=/docs/programmer/net/tipsofgrpc/>gRpc使用小记</a></li><li><a href=/docs/programmer/net/net/>网络(Computer Network)</a></li><li><a href=/docs/programmer/net/elk%E5%9C%A8k8s%E4%B8%8A%E7%9A%84%E9%83%A8%E7%BD%B2%E4%BD%BF%E7%94%A8%E7%A4%BA%E4%BE%8B/>Elk在k8s上的部署使用示例</a></li><li><a href=/docs/programmer/net/nginx%E5%AE%9E%E7%94%A8%E9%85%8D%E7%BD%AE/>Nginx实用配置</a></li></ul></li><li><input type=checkbox id=section-bf4e0d6f0b81f7b3ec08ed1fc66b874d class=toggle>
<label for=section-bf4e0d6f0b81f7b3ec08ed1fc66b874d class="flex justify-between"><a role=button>Langs</a></label><ul><li><a href=/docs/programmer/langs/cmake/>CMake 使用Tips</a></li><li><a href=/docs/programmer/langs/noteofgoexp/>Golang进阶笔记</a></li><li><a href=/docs/programmer/langs/noteofgolang/>Golang笔记</a></li><li><a href=/docs/programmer/langs/tipsofmarkdown/>tips Of markdown</a></li><li><a href=/docs/programmer/langs/notespython/>Python笔记(notes of Python)</a></li><li><a href=/docs/programmer/langs/notesjava/>愉快的Java(happy to learn the fuck java)</a></li></ul></li><li><input type=checkbox id=section-cd029da01a5cf373a5379dc078a74f2c class=toggle>
<label for=section-cd029da01a5cf373a5379dc078a74f2c class="flex justify-between"><a role=button>Game and Simulation</a></label><ul><li><a href=/docs/programmer/game_and_simulation/blender/>Blender</a></li><li><a href=/docs/programmer/game_and_simulation/noteofue4/>UE4 笔记</a></li></ul></li><li><input type=checkbox id=section-883e27361d38e16afb68faff3435ac0b class=toggle>
<label for=section-883e27361d38e16afb68faff3435ac0b class="flex justify-between"><a role=button>Ml</a></label><ul><li><a href=/docs/programmer/ml/tensorflow/>Tensorflow</a></li><li><a href=/docs/programmer/ml/opencv/>OpenCV</a></li><li><a href=/docs/programmer/ml/paddle/>Paddle</a></li><li><a href=/docs/programmer/ml/noteofmachinelearning/>机器学习库</a></li></ul></li><li><input type=checkbox id=section-7e5360c5e7954906b897ed79085884b6 class=toggle>
<label for=section-7e5360c5e7954906b897ed79085884b6 class="flex justify-between"><a href=/docs/programmer/gui/>Gui</a></label><ul><li><a href=/docs/programmer/gui/pyinstaller/>python打包</a></li><li><a href=/docs/programmer/gui/qt/>Qt/PySide</a></li><li><a href=/docs/programmer/gui/noteofvn_py/>Vn.Py学习笔记（Python交易平台框架）</a></li><li><a href=/docs/programmer/gui/notespython/>图形化界面 （Python Gui）</a></li></ul></li><li><input type=checkbox id=section-4446dd07527142b855f26d7cc8f0e617 class=toggle>
<label for=section-4446dd07527142b855f26d7cc8f0e617 class="flex justify-between"><a role=button>Database</a></label><ul><li><a href=/docs/programmer/database/dgraph/>Dgraph使用小记</a></li><li><a href=/docs/programmer/database/noteofdocker/>notes Of docker</a></li><li><a href=/docs/programmer/database/noteofdbdata/>db数据库</a></li><li><a href=/docs/programmer/database/mongodb/>Mongodb</a></li></ul></li><li><input type=checkbox id=section-d325c59fc6513e1b1e05a60b192d4973 class=toggle>
<label for=section-d325c59fc6513e1b1e05a60b192d4973 class="flex justify-between"><a href=/docs/programmer/hardware/>Hardware</a></label><ul><li><a href=/docs/programmer/hardware/android/>Android</a></li><li><a href=/docs/programmer/hardware/raspberrypi/>Raspberry Pi</a></li><li><a href=/docs/programmer/hardware/readme/>Readme</a></li><li><a href=/docs/programmer/hardware/screen/>Screen</a></li></ul></li><li><input type=checkbox id=section-40d35e91afa620ff2e7bf6291cfb3e1d class=toggle>
<label for=section-40d35e91afa620ff2e7bf6291cfb3e1d class="flex justify-between"><a href=/docs/programmer/software/>Software</a></label><ul><li><a href=/docs/programmer/software/bash/>Bash</a></li><li><a href=/docs/programmer/software/freebsd/>Freebsd</a></li><li><a href=/docs/programmer/software/gitbook/>Gitbook</a></li><li><a href=/docs/programmer/software/markdown/>Markdown</a></li><li><a href=/docs/programmer/software/npm/>Npm</a></li><li><a href=/docs/programmer/software/readme/>Readme</a></li><li><a href=/docs/programmer/software/vim/>Vim</a></li></ul></li><li><a href=/docs/programmer/install_some/>安装问题</a></li><li><a href=/docs/programmer/demo_test_some/>Demo Test项目中的一些东西</a></li><li><a href=/docs/programmer/tipsofproblems/>解决问题</a></li></ul></li><li class=book-section-flat><a href=/docs/example/>Hugo特殊Markdown语法说明</a><ul><li><a href=/docs/example/table-of-contents/>Table of Contents</a><ul><li><a href=/docs/example/table-of-contents/with-toc/>With ToC</a></li><li><a href=/docs/example/table-of-contents/without-toc/>Without ToC</a></li></ul></li><li class=book-section-flat><span>Shortcodes</span><ul><li><a href=/docs/example/shortcodes/buttons/>Buttons</a></li><li><a href=/docs/example/shortcodes/columns/>Columns</a></li><li><a href=/docs/example/shortcodes/details/>Details</a></li><li><a href=/docs/example/shortcodes/expand/>Expand</a></li><li><a href=/docs/example/shortcodes/hints/>Hints</a></li><li><input type=checkbox id=section-1c6a8516f710b6065a114907cef8489f class=toggle>
<label for=section-1c6a8516f710b6065a114907cef8489f class="flex justify-between"><a href=/docs/example/shortcodes/section/>Section</a></label><ul><li><a href=/docs/example/shortcodes/section/first-page/>First Page</a></li><li><a href=/docs/example/shortcodes/section/second-page/>Second Page</a></li></ul></li><li><a href=/docs/example/shortcodes/tabs/>Tabs</a></li></ul></li></ul></li></ul><ul><li><a href=/posts/>Blog</a></li></ul></nav><script>(function(){var e=document.querySelector("aside .book-menu-content");addEventListener("beforeunload",function(){localStorage.setItem("menu.scrollTop",e.scrollTop)}),e.scrollTop=localStorage.getItem("menu.scrollTop")})()</script></div></aside><div class=book-page><header class=book-header><div class="flex align-center justify-between"><label for=menu-control><img src=/svg/menu.svg class=book-icon alt=Menu>
</label><strong>Py Test 测试</strong>
<label for=toc-control><img src=/svg/toc.svg class=book-icon alt="Table of Contents"></label></div><aside class="hidden clearfix"><nav id=TableOfContents><ul><li><a href=#django-整合进-pytest测试>Django 整合进 pytest测试</a></li><li><a href=#一为什么需要pytest>一、为什么需要pytest</a><ul><li><a href=#简单例子>简单例子</a></li><li><a href=#常用命令>常用命令</a></li><li><a href=#安装>安装</a></li></ul></li><li><a href=#二api测试>二、API测试</a><ul><li><a href=#简单且重复的接口测试-以csv为例>简单且重复的接口测试 <strong>以CSV为例</strong></a></li></ul></li><li><a href=#三mock-和测试>三、Mock 和测试</a><ul><li><a href=#0-mock的方式>0. Mock的方式</a></li><li><a href=#1-mock一个方法>1. Mock一个方法</a></li><li><a href=#2-mock一个类>2. Mock一个类</a></li><li><a href=#3-实例>3. 实例</a></li></ul></li><li><a href=#四功能重用pytestfixture>四、功能重用(pytest.fixture)</a><ul><li><a href=#fixture作用范围scope>fixture作用范围(scope)</a></li></ul></li><li><a href=#五流程规范allure>五、流程规范(Allure)</a></li></ul></nav></aside></header><article class=markdown><p>[TOC]</p><h1 id=命令>命令
<a class=anchor href=#%e5%91%bd%e4%bb%a4>#</a></h1><h2 id=django-整合进-pytest测试>Django 整合进 pytest测试
<a class=anchor href=#django-%e6%95%b4%e5%90%88%e8%bf%9b-pytest%e6%b5%8b%e8%af%95>#</a></h2><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>pip install pytest-django
</span></span><span style=display:flex><span>pytest -s -vv .<span style=color:#ae81ff>\t</span>ests<span style=color:#ae81ff>\t</span>est_step2.py  --rootdir X:<span style=color:#ae81ff>\C</span>ode<span style=color:#ae81ff>\w</span>orkflows<span style=color:#ae81ff>\ </span>--ds project.settings
</span></span></code></pre></div><ul><li>rootdir 指定项目根目录</li><li>ds 指向django <code>setting.py</code> 文件</li></ul><h2 id=一为什么需要pytest>一、为什么需要pytest
<a class=anchor href=#%e4%b8%80%e4%b8%ba%e4%bb%80%e4%b9%88%e9%9c%80%e8%a6%81pytest>#</a></h2><p><code>helps you write better programs</code></p><ul><li>提高阅读理解代码效率</li><li>提高debug效率</li><li>提高开发效率</li><li>保证交付代码质量</li></ul><h3 id=简单例子>简单例子
<a class=anchor href=#%e7%ae%80%e5%8d%95%e4%be%8b%e5%ad%90>#</a></h3><blockquote><p>入门例子:</p></blockquote><ol><li>了解使用test文件命名格式: <code>test_</code>前缀</li><li>了解断言<code>assert</code></li><li>了解测试输出</li></ol><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#75715e># content of test_sample.py</span>
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>inc</span>(x):
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>return</span> x <span style=color:#f92672>+</span> <span style=color:#ae81ff>1</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>test_answer</span>():
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>assert</span> inc(<span style=color:#ae81ff>3</span>) <span style=color:#f92672>==</span> <span style=color:#ae81ff>5</span>
</span></span></code></pre></div><blockquote><p>输出</p></blockquote><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>$ pytest
</span></span><span style=display:flex><span><span style=color:#f92672>===========================</span> test session starts <span style=color:#f92672>============================</span>
</span></span><span style=display:flex><span>platform linux -- Python 3.x.y, pytest-7.x.y, pluggy-1.x.y
</span></span><span style=display:flex><span>rootdir: /home/sweet/project
</span></span><span style=display:flex><span>collected <span style=color:#ae81ff>1</span> item
</span></span><span style=display:flex><span>test_sample.py F                                                     <span style=color:#f92672>[</span>100%<span style=color:#f92672>]</span>
</span></span><span style=display:flex><span><span style=color:#f92672>=================================</span> FAILURES <span style=color:#f92672>=================================</span>
</span></span><span style=display:flex><span>_______________________________ test_answer ________________________________
</span></span><span style=display:flex><span>    def test_answer<span style=color:#f92672>()</span>:
</span></span><span style=display:flex><span>&gt;       assert inc<span style=color:#f92672>(</span>3<span style=color:#f92672>)</span> <span style=color:#f92672>==</span> <span style=color:#ae81ff>5</span>
</span></span><span style=display:flex><span>E       assert 4 <span style=color:#f92672>==</span> <span style=color:#ae81ff>5</span>
</span></span><span style=display:flex><span>E        +  where 4 <span style=color:#f92672>=</span> inc<span style=color:#f92672>(</span>3<span style=color:#f92672>)</span>
</span></span><span style=display:flex><span>test_sample.py:6: AssertionError
</span></span><span style=display:flex><span><span style=color:#f92672>=========================</span> short test summary info <span style=color:#f92672>==========================</span>
</span></span><span style=display:flex><span>FAILED test_sample.py::test_answer - assert 4 <span style=color:#f92672>==</span> 5
</span></span><span style=display:flex><span><span style=color:#f92672>============================</span> <span style=color:#ae81ff>1</span> failed in 0.12s <span style=color:#f92672>=============================</span>
</span></span></code></pre></div><h3 id=常用命令>常用命令
<a class=anchor href=#%e5%b8%b8%e7%94%a8%e5%91%bd%e4%bb%a4>#</a></h3><p><code>熟悉测试命令和备忘, 了解常用参数含义</code></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>pytest -s 输出print和日志
</span></span><span style=display:flex><span>    --pdb 允许pdb调试
</span></span><span style=display:flex><span>    -vv 详细输出
</span></span></code></pre></div><h4 id=django>Django
<a class=anchor href=#django>#</a></h4><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>python2 manage.py test tests/ <span style=color:#75715e># Django Test</span>
</span></span></code></pre></div><h4 id=allure>Allure
<a class=anchor href=#allure>#</a></h4><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>pytest --alluredir<span style=color:#f92672>=</span>./allure_report
</span></span><span style=display:flex><span>allure serve ./allure_report
</span></span></code></pre></div><h3 id=安装>安装
<a class=anchor href=#%e5%ae%89%e8%a3%85>#</a></h3><p><code>涉及到的库和依赖安装命令备忘</code></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>apt install npm
</span></span><span style=display:flex><span>apt install openjdk-11-jdk
</span></span><span style=display:flex><span>npm install -g allure-commandline --save-dev
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>pip install pytest
</span></span><span style=display:flex><span>pip install allure-pytest
</span></span><span style=display:flex><span><span style=color:#75715e># -i https://pypi.tuna.tsinghua.edu.cn/simple</span>
</span></span></code></pre></div><h2 id=二api测试>二、API测试
<a class=anchor href=#%e4%ba%8capi%e6%b5%8b%e8%af%95>#</a></h2><p><code>批量API测试简化写法, 初步体验一下简化工作的快乐</code></p><h3 id=简单且重复的接口测试-以csv为例>简单且重复的接口测试 <strong>以CSV为例</strong>
<a class=anchor href=#%e7%ae%80%e5%8d%95%e4%b8%94%e9%87%8d%e5%a4%8d%e7%9a%84%e6%8e%a5%e5%8f%a3%e6%b5%8b%e8%af%95-%e4%bb%a5csv%e4%b8%ba%e4%be%8b>#</a></h3><h4 id=testcsv><code>test.csv</code>
<a class=anchor href=#testcsv>#</a></h4><table><thead><tr><th>url</th><th>body</th><th>contains</th></tr></thead><tbody><tr><td><a href=https://httpbin.org/post>https://httpbin.org/post</a></td><td>{&ldquo;key&rdquo;: &ldquo;value&rdquo;}</td><td>{&ldquo;url&rdquo;: &ldquo;<a href=https://httpbin.org/post%22%7d>https://httpbin.org/post"}</a></td></tr><tr><td><a href=https://httpbin.org/post>https://httpbin.org/post</a></td><td>{&ldquo;key&rdquo;: &ldquo;value&rdquo;}</td><td>{&ldquo;data&rdquo;: &ldquo;{"key": "value"}&rdquo;}</td></tr></tbody></table><h4 id=test_apipy><code>test_api.py</code>
<a class=anchor href=#test_apipy>#</a></h4><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>readCsv</span>():
</span></span><span style=display:flex><span>   data<span style=color:#f92672>=</span>list()
</span></span><span style=display:flex><span>   <span style=color:#66d9ef>with</span> open(<span style=color:#e6db74>&#39;test.csv&#39;</span>,<span style=color:#e6db74>&#39;r&#39;</span>) <span style=color:#66d9ef>as</span> f:
</span></span><span style=display:flex><span>      reader<span style=color:#f92672>=</span>csv<span style=color:#f92672>.</span>reader(f)
</span></span><span style=display:flex><span>      next(reader)
</span></span><span style=display:flex><span>      <span style=color:#66d9ef>for</span> item <span style=color:#f92672>in</span> reader:
</span></span><span style=display:flex><span>         data<span style=color:#f92672>.</span>append(item)
</span></span><span style=display:flex><span>   <span style=color:#66d9ef>return</span> data
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#a6e22e>@pytest.mark.parametrize</span>(<span style=color:#e6db74>&#39;data&#39;</span>, readCsv())
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>test_csv_login</span>(data):
</span></span><span style=display:flex><span>    r<span style=color:#f92672>=</span>requests<span style=color:#f92672>.</span>post(
</span></span><span style=display:flex><span>        url<span style=color:#f92672>=</span>data[<span style=color:#ae81ff>0</span>],
</span></span><span style=display:flex><span>        json<span style=color:#f92672>=</span>json<span style=color:#f92672>.</span>loads(data[<span style=color:#ae81ff>1</span>]))
</span></span><span style=display:flex><span>    _temp <span style=color:#f92672>=</span> r<span style=color:#f92672>.</span>json()
</span></span><span style=display:flex><span>    _temp_update <span style=color:#f92672>=</span> copy<span style=color:#f92672>.</span>deepcopy(_temp)
</span></span><span style=display:flex><span>    _temp_update<span style=color:#f92672>.</span>update(json<span style=color:#f92672>.</span>loads(data[<span style=color:#ae81ff>2</span>]))
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>assert</span> _temp <span style=color:#f92672>==</span> _temp_update
</span></span></code></pre></div><blockquote><p>输出</p></blockquote><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>pytest test_api.py
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#f92672>====================================</span> test session starts <span style=color:#f92672>====================================</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>platform linux -- Python 3.9.2, pytest-7.2.1, pluggy-1.0.0
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>rootdir: /mnt/share/code
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>plugins: allure-pytest-2.12.0, anyio-3.6.2
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>collected <span style=color:#ae81ff>2</span> items
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>  
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>test_api.py ..                                                                        <span style=color:#f92672>[</span>100%<span style=color:#f92672>]</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#f92672>=====================================</span> <span style=color:#ae81ff>2</span> passed in 3.12s <span style=color:#f92672>=====================================</span>
</span></span></code></pre></div><h2 id=三mock-和测试>三、Mock 和测试
<a class=anchor href=#%e4%b8%89mock-%e5%92%8c%e6%b5%8b%e8%af%95>#</a></h2><p><code>了解测试中常用的小工具, 增进开发自测幸福感</code></p><ul><li>前、后端并行开发, 摆脱依赖</li><li>模拟无法访问的资源</li><li>隔离系统, 避免脏数据干扰或生产脏数据</li></ul><h3 id=0-mock的方式>0. Mock的方式
<a class=anchor href=#0-mock%e7%9a%84%e6%96%b9%e5%bc%8f>#</a></h3><h4 id=i-手动指定-mock-范围>i. 手动指定 <code>mock</code> 范围
<a class=anchor href=#i-%e6%89%8b%e5%8a%a8%e6%8c%87%e5%ae%9a-mock-%e8%8c%83%e5%9b%b4>#</a></h4><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>test_get_sum</span>():
</span></span><span style=display:flex><span>    mock_get_sum <span style=color:#f92672>=</span> mock<span style=color:#f92672>.</span>patch(<span style=color:#e6db74>&#34;app.get_sum&#34;</span>, return_value<span style=color:#f92672>=</span><span style=color:#ae81ff>20</span>)
</span></span><span style=display:flex><span>    mock_get_sum<span style=color:#f92672>.</span>start()
</span></span><span style=display:flex><span>    rst <span style=color:#f92672>=</span> app<span style=color:#f92672>.</span>get_sum(<span style=color:#ae81ff>1</span>, <span style=color:#ae81ff>3</span>)
</span></span><span style=display:flex><span>    mock_get_sum<span style=color:#f92672>.</span>stop()
</span></span></code></pre></div><h4 id=ii-装饰器>ii. 装饰器
<a class=anchor href=#ii-%e8%a3%85%e9%a5%b0%e5%99%a8>#</a></h4><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#a6e22e>@mock.patch</span>(<span style=color:#e6db74>&#34;app.get_sum&#34;</span>)
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>test_get_sumv2</span>(mock_get_sum):
</span></span><span style=display:flex><span>    mock_get_sum<span style=color:#f92672>.</span>side_effect <span style=color:#f92672>=</span> mock_sum
</span></span><span style=display:flex><span>    rst <span style=color:#f92672>=</span> app<span style=color:#f92672>.</span>get_sum(<span style=color:#ae81ff>1</span>, <span style=color:#ae81ff>3</span>)
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>assert</span> rst <span style=color:#f92672>==</span> <span style=color:#ae81ff>10</span>
</span></span></code></pre></div><h4 id=iii-上下文管理器>iii. 上下文管理器
<a class=anchor href=#iii-%e4%b8%8a%e4%b8%8b%e6%96%87%e7%ae%a1%e7%90%86%e5%99%a8>#</a></h4><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#66d9ef>with</span> mock<span style=color:#f92672>.</span>patch(<span style=color:#e6db74>&#34;app.get_sum&#34;</span>, new_callable<span style=color:#f92672>=</span>mock_sum) <span style=color:#66d9ef>as</span> mock_get_sum:
</span></span><span style=display:flex><span>    rst <span style=color:#f92672>=</span> app<span style=color:#f92672>.</span>get_sum
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>assert</span> rst <span style=color:#f92672>==</span> <span style=color:#ae81ff>10</span>
</span></span></code></pre></div><h4 id=总结>总结
<a class=anchor href=#%e6%80%bb%e7%bb%93>#</a></h4><table><thead><tr><th>-</th><th>手动指定</th><th>装饰器</th><th>上下文管理器</th></tr></thead><tbody><tr><td>优点</td><td>可以更精细控制mock的范围</td><td>方便mock多个对象</td><td>1</td></tr><tr><td>不足</td><td>需要手动start和stop</td><td>装饰器顺序和函数参数相反容易混乱</td><td>一个with只能mock一个对象</td></tr></tbody></table><h3 id=1-mock一个方法>1. Mock一个方法
<a class=anchor href=#1-mock%e4%b8%80%e4%b8%aa%e6%96%b9%e6%b3%95>#</a></h3><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#f92672>from</span> pathlib <span style=color:#f92672>import</span> Path
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>test_getssh</span>(monkeypatch):
</span></span><span style=display:flex><span>    monkeypatch<span style=color:#f92672>.</span>setattr(Path, <span style=color:#e6db74>&#34;home&#34;</span>, mockreturn)
</span></span></code></pre></div><h3 id=2-mock一个类>2. Mock一个类
<a class=anchor href=#2-mock%e4%b8%80%e4%b8%aa%e7%b1%bb>#</a></h3><p><code>以 requests 为例, mock get 任意url的(.json())返回值</code></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#f92672>import</span> requests
</span></span><span style=display:flex><span><span style=color:#66d9ef>class</span> <span style=color:#a6e22e>App</span>:
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>def</span> <span style=color:#a6e22e>get_json</span>(self, url):
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>return</span> requests<span style=color:#f92672>.</span>get(url)<span style=color:#f92672>.</span>json()
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#66d9ef>class</span> <span style=color:#a6e22e>MockResponse</span>:
</span></span><span style=display:flex><span>    <span style=color:#a6e22e>@staticmethod</span>
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>def</span> <span style=color:#a6e22e>json</span>():
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>return</span> {<span style=color:#e6db74>&#34;mock_key&#34;</span>: <span style=color:#e6db74>&#34;mock_response&#34;</span>}
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>test_get_json</span>(monkeypatch):
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>def</span> <span style=color:#a6e22e>mock_get</span>(<span style=color:#f92672>*</span>args, <span style=color:#f92672>**</span>kwargs):
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>return</span> MockResponse()
</span></span><span style=display:flex><span>        
</span></span><span style=display:flex><span>    monkeypatch<span style=color:#f92672>.</span>setattr(requests, <span style=color:#e6db74>&#34;get&#34;</span>, mock_get)
</span></span><span style=display:flex><span>    result <span style=color:#f92672>=</span> App()<span style=color:#f92672>.</span>get_json(<span style=color:#e6db74>&#34;https://fakeurl&#34;</span>)
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>assert</span> result[<span style=color:#e6db74>&#34;mock_key&#34;</span>] <span style=color:#f92672>==</span> <span style=color:#e6db74>&#34;mock_response&#34;</span>
</span></span></code></pre></div><h3 id=3-实例>3. 实例
<a class=anchor href=#3-%e5%ae%9e%e4%be%8b>#</a></h3><h4 id=backent---django-test><strong>backent - Django Test</strong>
<a class=anchor href=#backent---django-test>#</a></h4><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#f92672>from</span> django.test <span style=color:#f92672>import</span> TestCase
</span></span><span style=display:flex><span><span style=color:#f92672>from</span> events.preview_service <span style=color:#f92672>import</span> PreviewService
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#66d9ef>class</span> <span style=color:#a6e22e>MailTestCase</span>(TestCase):
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>def</span> <span style=color:#a6e22e>setUp</span>(self):
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>pass</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>    <span style=color:#a6e22e>@patch</span>(<span style=color:#e6db74>&#39;events.preview_service.get_app_platform_logo&#39;</span>)
</span></span><span style=display:flex><span>    <span style=color:#a6e22e>@patch</span>(<span style=color:#e6db74>&#39;events.preview_service.is_master_node&#39;</span>)
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>def</span> <span style=color:#a6e22e>test_preview_info_master</span>(self, mock_node, mock_logo):
</span></span><span style=display:flex><span>        mock_node<span style=color:#f92672>.</span>return_value <span style=color:#f92672>=</span> <span style=color:#66d9ef>True</span>
</span></span><span style=display:flex><span>        base64_image <span style=color:#f92672>=</span> <span style=color:#e6db74>&#34;R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs=&#34;</span> <span style=color:#75715e># 黑色图片</span>
</span></span><span style=display:flex><span>        mock_logo<span style=color:#f92672>.</span>return_value <span style=color:#f92672>=</span> (<span style=color:#ae81ff>2000</span>, base64_image)
</span></span><span style=display:flex><span>        cnt <span style=color:#f92672>=</span> PreviewService({
</span></span><span style=display:flex><span>            <span style=color:#e6db74>&#34;notice_object&#34;</span>: <span style=color:#e6db74>&#34;customer&#34;</span>,
</span></span><span style=display:flex><span>            <span style=color:#e6db74>&#34;event_object&#34;</span>: {
</span></span><span style=display:flex><span>                <span style=color:#e6db74>&#34;event_list&#34;</span>: [
</span></span><span style=display:flex><span>                {
</span></span><span style=display:flex><span>                    <span style=color:#e6db74>&#34;start_time&#34;</span>: <span style=color:#e6db74>&#34;2023-01-16&#34;</span>,
</span></span><span style=display:flex><span>                    <span style=color:#e6db74>&#34;end_time&#34;</span>: <span style=color:#e6db74>&#34;2023-01-16&#34;</span>,
</span></span><span style=display:flex><span>                    <span style=color:#e6db74>&#34;customer_name&#34;</span>: <span style=color:#e6db74>&#34;6&#34;</span>,
</span></span><span style=display:flex><span>                }
</span></span><span style=display:flex><span>            ]}
</span></span><span style=display:flex><span>        })<span style=color:#f92672>.</span>get_preview_info()
</span></span><span style=display:flex><span>        self<span style=color:#f92672>.</span>assertEqual(type(cnt), dict)
</span></span><span style=display:flex><span>        self<span style=color:#f92672>.</span>assertEqual(cnt<span style=color:#f92672>.</span>keys(), {<span style=color:#e6db74>&#34;flag&#34;</span>: <span style=color:#66d9ef>None</span>, <span style=color:#e6db74>&#34;preview_info&#34;</span>: <span style=color:#66d9ef>None</span>, <span style=color:#e6db74>&#34;sender&#34;</span>: <span style=color:#66d9ef>None</span>}<span style=color:#f92672>.</span>keys())
</span></span><span style=display:flex><span>        self<span style=color:#f92672>.</span>assertEqual(cnt[<span style=color:#e6db74>&#34;flag&#34;</span>], <span style=color:#66d9ef>True</span>)
</span></span><span style=display:flex><span>        self<span style=color:#f92672>.</span>assertEqual(cnt[<span style=color:#e6db74>&#34;sender&#34;</span>][<span style=color:#e6db74>&#34;address&#34;</span>], <span style=color:#e6db74>&#34;mdr@nsfocus.com&#34;</span>)
</span></span><span style=display:flex><span>        self<span style=color:#f92672>.</span>assertEqual(cnt[<span style=color:#e6db74>&#34;preview_info&#34;</span>][<span style=color:#e6db74>&#34;email_title&#34;</span>], <span style=color:#e6db74>u</span><span style=color:#e6db74>&#34;【绿盟科技1】MDR威胁分析服务安全事件通知&#34;</span>)
</span></span></code></pre></div><h4 id=moc><strong>MOC</strong>
<a class=anchor href=#moc>#</a></h4><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#f92672>from</span> common.nscloud <span style=color:#f92672>import</span> NsCloudNuriClient
</span></span><span style=display:flex><span><span style=color:#66d9ef>class</span> <span style=color:#a6e22e>MockResponse</span>:
</span></span><span style=display:flex><span>    <span style=color:#a6e22e>@staticmethod</span>
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>def</span> <span style=color:#a6e22e>json</span>():
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>return</span> {<span style=color:#e6db74>&#34;results&#34;</span>: []}
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>test_a</span>(monkeypatch):
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>def</span> <span style=color:#a6e22e>mock_request</span>(<span style=color:#f92672>*</span>args, <span style=color:#f92672>**</span>kwargs):
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>return</span> MockResponse()
</span></span><span style=display:flex><span>    monkeypatch<span style=color:#f92672>.</span>setattr(NsCloudNuriClient, <span style=color:#e6db74>&#34;request&#34;</span>, mock_request)
</span></span><span style=display:flex><span>    <span style=color:#75715e># import pdb; pdb.set_trace()</span>
</span></span><span style=display:flex><span>    content <span style=color:#f92672>=</span> generate_daily_report_content(<span style=color:#e6db74>&#34;&#34;</span>, <span style=color:#e6db74>&#34;&#34;</span>)
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>assert</span> bool(content)
</span></span></code></pre></div><h2 id=四功能重用pytestfixture>四、功能重用(pytest.fixture)
<a class=anchor href=#%e5%9b%9b%e5%8a%9f%e8%83%bd%e9%87%8d%e7%94%a8pytestfixture>#</a></h2><p><code>fixture一点需要考虑的是初始化与清理。</code></p><ul><li>也就是说在一个完整的测试用例中, 都必须都得有初始化与清理的部分, 这样才是一个完整的测试用例的</li><li>还有一点是<code>fixture</code>的函数也可以和返回值整合起来构成完整流程, 以<code>get</code>案例, 那么首先需要<code>add</code>书籍, 然后是<code>get</code>, 最后是<code>del</code></li></ul><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#75715e>#!coding:utf-8</span>
</span></span><span style=display:flex><span><span style=color:#f92672>import</span> pytest
</span></span><span style=display:flex><span><span style=color:#f92672>import</span>  requests
</span></span><span style=display:flex><span><span style=color:#f92672>from</span> loguru <span style=color:#f92672>import</span> logger
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>add_book</span>(get_token):
</span></span><span style=display:flex><span>    r<span style=color:#f92672>=</span>requests<span style=color:#f92672>.</span>post(
</span></span><span style=display:flex><span>        url<span style=color:#f92672>=</span><span style=color:#e6db74>&#39;https://www.example.org/&#39;</span>,
</span></span><span style=display:flex><span>        headers<span style=color:#f92672>=</span>{<span style=color:#e6db74>&#39;Authorization&#39;</span>:<span style=color:#e6db74>&#39;JWT </span><span style=color:#e6db74>{0}</span><span style=color:#e6db74>&#39;</span><span style=color:#f92672>.</span>format(get_token)}
</span></span><span style=display:flex><span>    )
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>del_book <span style=color:#f92672>=</span> add_book <span style=color:#75715e># 仅演示用</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#a6e22e>@pytest.fixture</span>()
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>init</span>(get_token):
</span></span><span style=display:flex><span>    add_book(get_token)
</span></span><span style=display:flex><span>    logger<span style=color:#f92672>.</span>info(<span style=color:#e6db74>&#34;add_book in init&#34;</span>)
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>yield</span>
</span></span><span style=display:flex><span>    del_book(get_token)
</span></span><span style=display:flex><span>    logger<span style=color:#f92672>.</span>info(<span style=color:#e6db74>&#34;del_book in init&#34;</span>)
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>test_get_book</span>(init, get_token):
</span></span><span style=display:flex><span>    r<span style=color:#f92672>=</span>requests<span style=color:#f92672>.</span>post(
</span></span><span style=display:flex><span>        url<span style=color:#f92672>=</span><span style=color:#e6db74>&#39;https://www.example.org/&#39;</span>,
</span></span><span style=display:flex><span>        headers<span style=color:#f92672>=</span>{<span style=color:#e6db74>&#39;Authorization&#39;</span>:<span style=color:#e6db74>&#39;JWT </span><span style=color:#e6db74>{0}</span><span style=color:#e6db74>&#39;</span><span style=color:#f92672>.</span>format(get_token)}
</span></span><span style=display:flex><span>    )
</span></span><span style=display:flex><span>    logger<span style=color:#f92672>.</span>info(<span style=color:#e6db74>&#34;get_book in test&#34;</span>)
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>assert</span> r<span style=color:#f92672>.</span>text
</span></span></code></pre></div><h3 id=fixture作用范围scope>fixture作用范围(scope)
<a class=anchor href=#fixture%e4%bd%9c%e7%94%a8%e8%8c%83%e5%9b%b4scope>#</a></h3><p><code>@pytest.fixture()</code>如果不写参数, 默认就是<code>scope="function"</code>
它的作用范围是每个测试用例来之前运行一次, 销毁代码在测试用例运行之后运行</p><p><em>详细如下:</em></p><ul><li><code>function</code> 每一个函数或方法都会调用</li><li><code>class</code> 每一个类调用一次, 一个类可以有多个方法</li><li><code>module</code> 每一个<code>.py</code>文件调用一次, 该文件内又有多个function和class</li><li><code>session</code> 是多个文件调用一次, 可以跨<code>.py</code>文件调用, 每个<code>.py</code>文件就是module</li></ul><p><strong>输出</strong></p><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-bash data-lang=bash><span style=display:flex><span>pytest test_api.py -s
</span></span><span style=display:flex><span>test_api.py 2023-02-07 15:38:22.906 | INFO     | test_api:init:17 - add_book in init
</span></span><span style=display:flex><span>2023-02-07 15:38:24.471 | INFO     | test_api:test_get_book:27 - get_book in test
</span></span><span style=display:flex><span>2023-02-07 15:38:25.894 | INFO     | test_api:init:20 - del_book in init
</span></span><span style=display:flex><span><span style=color:#f92672>================</span> <span style=color:#ae81ff>1</span> passed in 6.71s <span style=color:#f92672>================</span>
</span></span></code></pre></div><h2 id=五流程规范allure>五、流程规范(Allure)
<a class=anchor href=#%e4%ba%94%e6%b5%81%e7%a8%8b%e8%a7%84%e8%8c%83allure>#</a></h2><ul><li>同样以<code>add</code>, <code>get</code>, <code>del</code>为例</li><li>详参<a href=https://blog.csdn.net/qq_42610167/article/details/101204066>这里</a> 和 <a href=https://www.w3cschool.cn/pytest/pytest-2is63m91.html>这里</a></li></ul><div class=highlight><pre tabindex=0 style=color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4><code class=language-python data-lang=python><span style=display:flex><span><span style=color:#f92672>import</span> allure
</span></span><span style=display:flex><span><span style=color:#f92672>import</span> pytest
</span></span><span style=display:flex><span><span style=color:#f92672>import</span> requests
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#a6e22e>@pytest.fixture</span>(scope<span style=color:#f92672>=</span><span style=color:#e6db74>&#34;session&#34;</span>)
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>login_setup</span>():
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>return</span> <span style=color:#e6db74>&#34;token&#34;</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#a6e22e>@allure.feature</span>(<span style=color:#e6db74>&#34;功能模块&#34;</span>)
</span></span><span style=display:flex><span><span style=color:#a6e22e>@allure.story</span>(<span style=color:#e6db74>&#34;测试用例小模块-成功案例&#34;</span>)
</span></span><span style=display:flex><span><span style=color:#a6e22e>@allure.title</span>(<span style=color:#e6db74>&#34;测试用例名称: 流程性的用例, 添加测试步骤&#34;</span>)
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>test_add_goods_and_buy</span>(login_setup):
</span></span><span style=display:flex><span>    <span style=color:#e6db74>&#39;&#39;&#39;
</span></span></span><span style=display:flex><span><span style=color:#e6db74>    用例描述:
</span></span></span><span style=display:flex><span><span style=color:#e6db74>    前置: 登陆
</span></span></span><span style=display:flex><span><span style=color:#e6db74>    用例步骤: 1.浏览商品 2.添加购物车  3.购买  4.支付成功
</span></span></span><span style=display:flex><span><span style=color:#e6db74>    &#39;&#39;&#39;</span>
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>with</span> allure<span style=color:#f92672>.</span>step(<span style=color:#e6db74>&#34;step1: 浏览商品&#34;</span>):
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>assert</span> <span style=color:#66d9ef>True</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>with</span> allure<span style=color:#f92672>.</span>step(<span style=color:#e6db74>&#34;step2: 添加购物车&#34;</span>):
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>assert</span> <span style=color:#66d9ef>True</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>with</span> allure<span style=color:#f92672>.</span>step(<span style=color:#e6db74>&#34;step3: 生成订单&#34;</span>):
</span></span><span style=display:flex><span>        <span style=color:#75715e># assert False</span>
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>assert</span> <span style=color:#66d9ef>True</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>with</span> allure<span style=color:#f92672>.</span>step(<span style=color:#e6db74>&#34;step4: 支付&#34;</span>):
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>assert</span> <span style=color:#66d9ef>True</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>with</span> allure<span style=color:#f92672>.</span>step(<span style=color:#e6db74>&#34;断言&#34;</span>):
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>assert</span> <span style=color:#66d9ef>True</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span><span style=color:#a6e22e>@allure.feature</span>(<span style=color:#e6db74>&#34;MDR服务邮件通知去绿盟云&#34;</span>)
</span></span><span style=display:flex><span><span style=color:#a6e22e>@allure.story</span>(<span style=color:#e6db74>&#34;客户安全事件邮件通知去绿盟化&#34;</span>)
</span></span><span style=display:flex><span><span style=color:#a6e22e>@allure.link</span>(<span style=color:#e6db74>&#34;https://inone.intra.nsfocus.com/jira/browse/MDR-4271&#34;</span>)
</span></span><span style=display:flex><span><span style=color:#a6e22e>@allure.title</span>(<span style=color:#e6db74>&#34;标题1&#34;</span>)
</span></span><span style=display:flex><span><span style=color:#66d9ef>def</span> <span style=color:#a6e22e>test_f1</span>():
</span></span><span style=display:flex><span>    <span style=color:#e6db74>&#39;&#39;&#39;
</span></span></span><span style=display:flex><span><span style=color:#e6db74>    用例描述:
</span></span></span><span style=display:flex><span><span style=color:#e6db74>    前置: 无
</span></span></span><span style=display:flex><span><span style=color:#e6db74>    用例步骤: 1.测试1 2.测试2
</span></span></span><span style=display:flex><span><span style=color:#e6db74>    &#39;&#39;&#39;</span>
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>with</span> allure<span style=color:#f92672>.</span>step(<span style=color:#e6db74>&#34;step1&#34;</span>):
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>assert</span> <span style=color:#66d9ef>True</span>
</span></span><span style=display:flex><span>
</span></span><span style=display:flex><span>    <span style=color:#66d9ef>with</span> allure<span style=color:#f92672>.</span>step(<span style=color:#e6db74>&#34;step2&#34;</span>):
</span></span><span style=display:flex><span>        <span style=color:#66d9ef>assert</span> <span style=color:#66d9ef>True</span>
</span></span></code></pre></div><p>![[pytest-demo.jpg]]</p></article><footer class=book-footer><div class="flex flex-wrap justify-between"></div><script>(function(){function e(e){const t=window.getSelection(),n=document.createRange();n.selectNodeContents(e),t.removeAllRanges(),t.addRange(n)}document.querySelectorAll("pre code").forEach(t=>{t.addEventListener("click",function(){if(window.getSelection().toString())return;e(t.parentElement),navigator.clipboard&&navigator.clipboard.writeText(t.parentElement.textContent)})})})()</script></footer><div class=book-comments></div><label for=menu-control class="hidden book-menu-overlay"></label></div><aside class=book-toc><div class=book-toc-content><nav id=TableOfContents><ul><li><a href=#django-整合进-pytest测试>Django 整合进 pytest测试</a></li><li><a href=#一为什么需要pytest>一、为什么需要pytest</a><ul><li><a href=#简单例子>简单例子</a></li><li><a href=#常用命令>常用命令</a></li><li><a href=#安装>安装</a></li></ul></li><li><a href=#二api测试>二、API测试</a><ul><li><a href=#简单且重复的接口测试-以csv为例>简单且重复的接口测试 <strong>以CSV为例</strong></a></li></ul></li><li><a href=#三mock-和测试>三、Mock 和测试</a><ul><li><a href=#0-mock的方式>0. Mock的方式</a></li><li><a href=#1-mock一个方法>1. Mock一个方法</a></li><li><a href=#2-mock一个类>2. Mock一个类</a></li><li><a href=#3-实例>3. 实例</a></li></ul></li><li><a href=#四功能重用pytestfixture>四、功能重用(pytest.fixture)</a><ul><li><a href=#fixture作用范围scope>fixture作用范围(scope)</a></li></ul></li><li><a href=#五流程规范allure>五、流程规范(Allure)</a></li></ul></nav></div></aside></main></body></html>